import tkinter as tk
import ttkbootstrap as ttk
from tkinter import filedialog, messagebox
import os
from pathlib import Path
import re


class BatchRenameApp:
    def __init__(self, root):
        self.root = root
        self.root.title("批量文件重命名工具")

        # 创建主题并设置颜色
        self.style = ttk.Style(theme="flatly")

        # 修改主题颜色
        self.style.colors.primary = "#9683EC"
        self.style.colors.secondary = "#9683EC"
        self.style.colors.success = "#9683EC"
        self.style.colors.info = "#9683EC"
        self.style.colors.warning = "#9683EC"
        self.style.colors.danger = "#9683EC"

        # 设置全局颜色
        self.style.configure(".",
                             background="white",
                             foreground="black")

        # 配置根窗口的行列权重，使组件能够随窗口大小变化
        self.root.grid_columnconfigure(0, weight=1)
        self.root.grid_rowconfigure(0, weight=1)

        # 创建主框架
        self.main_frame = ttk.Frame(self.root, padding="20")
        self.main_frame.grid(row=0, column=0, sticky="nsew")

        # 配置主框架的行列权重
        self.main_frame.grid_columnconfigure(0, weight=1)

        # 存储选择的文件
        self.selected_files = []
        # 存储基础路径（用于文件夹模式显示相对路径）
        self.base_folder = None

        # 选择文件按钮和文件列表框架
        self.source_frame = ttk.LabelFrame(self.main_frame, text="加载文件路径", padding="10")
        self.source_frame.grid(row=0, column=0, sticky="ew", pady=(0, 10))

        # 添加模式选择单选按钮
        mode_frame = ttk.Frame(self.source_frame)
        mode_frame.grid(row=0, column=0, sticky="w", pady=(0, 5))

        ttk.Label(mode_frame, text="选择模式:").pack(side=tk.LEFT, padx=(0, 10))
        self.select_mode_var = tk.StringVar(value="files")
        ttk.Radiobutton(mode_frame, text="选择文件",
                        variable=self.select_mode_var, value="files",
                        bootstyle="danger-round-toggle").pack(side=tk.LEFT, padx=(0, 20))
        ttk.Radiobutton(mode_frame, text="选择文件夹(递归所有子文件夹)",
                        variable=self.select_mode_var, value="folder",
                        bootstyle="danger-round-toggle").pack(side=tk.LEFT)

        # 浏览按钮和文件列表
        browse_frame = ttk.Frame(self.source_frame)
        browse_frame.grid(row=1, column=0, sticky="ew")
        browse_frame.grid_columnconfigure(0, weight=1)

        self.file_listbox = ttk.Treeview(browse_frame, columns=("path",), show="", height=4)
        self.file_listbox.grid(row=0, column=0, sticky="ew", padx=(0, 10))

        self.select_btn = ttk.Button(
            browse_frame,
            text="浏览",
            command=self.select_files,
            bootstyle="danger"
        )
        self.select_btn.grid(row=0, column=1, sticky="e")

        self.source_frame.grid_columnconfigure(0, weight=1)

        # 添加文件名修改主框架
        original_name_frame = ttk.LabelFrame(self.main_frame, text="文件名修改", padding="10")
        original_name_frame.grid(row=1, column=0, sticky="ew", pady=(0, 10))

        # 删除使用原文件名选项
        self.use_original_var = tk.BooleanVar(value=True)  # 默认使用原文件名，但不显示在UI上

        # 创建选项卡控件
        self.notebook = ttk.Notebook(original_name_frame)
        self.notebook.pack(fill=tk.X, expand=True)

        # 自定义选项卡样式，使其与主题紫色一致
        self.style.configure('TNotebook.Tab', foreground='white', background=self.style.colors.primary, padding=[60, 5])
        self.style.map('TNotebook.Tab',
                       background=[('selected', self.style.colors.primary), ('active', '#a797f0')],
                       foreground=[('selected', 'white'), ('active', 'white')])

        # 配置选项卡内容区域样式
        self.style.configure("Purple.TFrame", background="#F4F0FF")  # 浅紫色背景

        # 1. 基本操作选项卡 - 包含查找替换、添加文本和序号设置
        basic_tab = ttk.Frame(self.notebook, padding=5, style="Purple.TFrame")
        self.notebook.add(basic_tab, text="       增添替换、编号       ")

        # 添加查找替换设置
        search_replace_frame = ttk.LabelFrame(basic_tab, text="查找替换", padding="5", bootstyle="primary")
        search_replace_frame.pack(fill=tk.X, pady=5)

        replace_frame = ttk.Frame(search_replace_frame)
        replace_frame.pack(fill=tk.X, pady=5)

        ttk.Label(replace_frame, text="查找内容:").pack(side=tk.LEFT)
        self.find_text_var = tk.StringVar()
        self.find_text_entry = ttk.Entry(replace_frame, textvariable=self.find_text_var, width=25)
        self.find_text_entry.pack(side=tk.LEFT, padx=(5, 20))

        ttk.Label(replace_frame, text="替换为:").pack(side=tk.LEFT)
        self.replace_text_var = tk.StringVar()
        self.replace_text_entry = ttk.Entry(replace_frame, textvariable=self.replace_text_var, width=26)
        self.replace_text_entry.pack(side=tk.LEFT, padx=5)

        # 添加前缀后缀设置
        add_text_label_frame = ttk.LabelFrame(basic_tab, text="添加文本", padding="5", bootstyle="primary")
        add_text_label_frame.pack(fill=tk.X, pady=5)

        add_text_frame = ttk.Frame(add_text_label_frame)
        add_text_frame.pack(fill=tk.X, pady=5)

        ttk.Label(add_text_frame, text="前面添加:").pack(side=tk.LEFT)
        self.prepend_text_var = tk.StringVar()
        self.prepend_text_entry = ttk.Entry(add_text_frame, textvariable=self.prepend_text_var, width=25)
        self.prepend_text_entry.pack(side=tk.LEFT, padx=(5, 20))

        ttk.Label(add_text_frame, text="后面添加:").pack(side=tk.LEFT)
        self.append_text_var = tk.StringVar()
        self.append_text_entry = ttk.Entry(add_text_frame, textvariable=self.append_text_var, width=25)
        self.append_text_entry.pack(side=tk.LEFT, padx=5)

        # 添加序号设置框架（移到基本操作选项卡）
        number_label_frame = ttk.LabelFrame(basic_tab, text="自动编号", padding="5", bootstyle="primary")
        number_label_frame.pack(fill=tk.X, pady=5)

        number_insert_frame = ttk.Frame(number_label_frame)
        number_insert_frame.pack(fill=tk.X, pady=5)

        # 添加序号起始值设置
        ttk.Label(number_insert_frame, text="起始序号:").pack(side=tk.LEFT)
        self.number_start_var = tk.StringVar(value="")
        self.number_start_entry = ttk.Entry(number_insert_frame, textvariable=self.number_start_var, width=10)
        self.number_start_entry.pack(side=tk.LEFT, padx=(5, 20))

        # 添加序号位置标记设置
        ttk.Label(number_insert_frame, text="位置标记:").pack(side=tk.LEFT)
        self.number_marker_var = tk.StringVar(value="@")
        self.number_marker_entry = ttk.Entry(number_insert_frame, textvariable=self.number_marker_var, width=5)
        self.number_marker_entry.pack(side=tk.LEFT, padx=5)
        ttk.Label(number_insert_frame, text="(查找替换、增添里可用此符号标记序号位置)").pack(side=tk.LEFT, padx=5)

        # 高级操作选项卡
        advanced_tab = ttk.Frame(self.notebook, padding=5, style="Purple.TFrame")
        self.notebook.add(advanced_tab, text="       字符删减、移动       ")

        # 简单修改选项卡
        simple_tab = ttk.Frame(self.notebook, padding=5, style="Purple.TFrame")
        self.notebook.add(simple_tab, text="       简单修改       ")

        # 在简单修改选项卡中添加保留原文件名选项
        self.use_original_simple_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(simple_tab, text="保留原文件名（只修改扩展名）",
                        variable=self.use_original_simple_var,
                        command=self.toggle_simple_rename_options,
                        bootstyle="danger-round-toggle").pack(anchor=tk.W, pady=(0, 5))

        # 创建包含前缀、后缀和编号设置的子框架
        self.simple_rename_options_frame = ttk.Frame(simple_tab)
        self.simple_rename_options_frame.pack(fill=tk.X)

        # 前缀和后缀输入框架
        simple_prefix_suffix_frame = ttk.LabelFrame(self.simple_rename_options_frame, text="前缀和后缀", padding="5", bootstyle="primary")
        simple_prefix_suffix_frame.pack(fill=tk.X, pady=5)

        simple_ps_frame = ttk.Frame(simple_prefix_suffix_frame)
        simple_ps_frame.pack(fill=tk.X, pady=5)

        ttk.Label(simple_ps_frame, text="前缀:").pack(side=tk.LEFT)
        self.simple_prefix_var = tk.StringVar()
        self.simple_prefix_entry = ttk.Entry(simple_ps_frame, textvariable=self.simple_prefix_var, width=20)
        self.simple_prefix_entry.pack(side=tk.LEFT, padx=(5, 20))

        ttk.Label(simple_ps_frame, text="后缀:").pack(side=tk.LEFT)
        self.simple_suffix_var = tk.StringVar()
        self.simple_suffix_entry = ttk.Entry(simple_ps_frame, textvariable=self.simple_suffix_var, width=20)
        self.simple_suffix_entry.pack(side=tk.LEFT, padx=5)

        # 编号设置框架
        simple_number_frame = ttk.LabelFrame(self.simple_rename_options_frame, text="编号设置", padding="5", bootstyle="primary")
        simple_number_frame.pack(fill=tk.X, pady=5)

        simple_num_frame = ttk.Frame(simple_number_frame)
        simple_num_frame.pack(fill=tk.X, pady=5)

        ttk.Label(simple_num_frame, text="起始编号:").pack(side=tk.LEFT)
        self.simple_start_num_var = tk.StringVar(value="1")
        self.simple_start_num_entry = ttk.Entry(simple_num_frame, textvariable=self.simple_start_num_var, width=10)
        self.simple_start_num_entry.pack(side=tk.LEFT, padx=(5, 20))

        ttk.Label(simple_num_frame, text="编号位数:").pack(side=tk.LEFT)
        self.simple_num_digits_var = tk.StringVar(value="2")
        self.simple_num_digits_entry = ttk.Entry(simple_num_frame, textvariable=self.simple_num_digits_var, width=10)
        self.simple_num_digits_entry.pack(side=tk.LEFT, padx=5)

        # 添加分段编号选项
        segment_frame = ttk.Frame(simple_number_frame)
        segment_frame.pack(fill=tk.X, pady=5)

        self.use_segment_numbering_var = tk.BooleanVar(value=False)
        ttk.Checkbutton(segment_frame, text="使用分段编号(每个子文件夹独立编号)",
                        variable=self.use_segment_numbering_var,
                        command=self.toggle_segment_numbering,
                        bootstyle="danger-round-toggle").pack(anchor=tk.W)

        # 分段编号配置框架
        self.segment_config_frame = ttk.Frame(simple_number_frame)
        self.segment_config_frame.pack(fill=tk.X, pady=5)

        ttk.Label(self.segment_config_frame, text="分段规则:").pack(side=tk.LEFT)
        self.segment_rules_var = tk.StringVar(value="1-6:1, 7-:4")
        self.segment_rules_entry = ttk.Entry(self.segment_config_frame, textvariable=self.segment_rules_var, width=30)
        self.segment_rules_entry.pack(side=tk.LEFT, padx=5)
        self.segment_rules_entry.configure(state="disabled")

        # 添加说明标签
        help_frame = ttk.Frame(simple_number_frame)
        help_frame.pack(fill=tk.X, pady=2)
        ttk.Label(help_frame, text="格式说明: 1-6:1 表示第1-6个用前缀1, 7-:4 表示第7个开始用前缀4",
                  font=("Arial", 8)).pack(anchor=tk.W, padx=5)

        # 扩展名修改框架
        simple_ext_frame = ttk.LabelFrame(simple_tab, text="扩展名修改", padding="5", bootstyle="primary")
        simple_ext_frame.pack(fill=tk.X, pady=5)

        simple_ext_inner_frame = ttk.Frame(simple_ext_frame)
        simple_ext_inner_frame.pack(fill=tk.X, pady=5)

        self.simple_ext_var = tk.StringVar(value="keep")
        ttk.Radiobutton(simple_ext_inner_frame, text="保持原扩展名",
                        variable=self.simple_ext_var, value="keep",
                        bootstyle="danger-round-toggle").pack(side=tk.LEFT, padx=(0, 20))
        ttk.Radiobutton(simple_ext_inner_frame, text="修改扩展名",
                        variable=self.simple_ext_var, value="change",
                        bootstyle="danger-round-toggle").pack(side=tk.LEFT, padx=(0, 20))

        ttk.Label(simple_ext_inner_frame, text="新扩展名:").pack(side=tk.LEFT)
        self.simple_new_ext_var = tk.StringVar()
        self.simple_new_ext_entry = ttk.Entry(simple_ext_inner_frame, textvariable=self.simple_new_ext_var, width=10)
        self.simple_new_ext_entry.pack(side=tk.LEFT, padx=5)
        ttk.Label(simple_ext_inner_frame, text="(例如: .txt)").pack(side=tk.LEFT, padx=5)

        # 添加字符删除功能框架
        char_delete_label_frame = ttk.LabelFrame(advanced_tab, text="字符删除", padding="5", bootstyle="primary")
        char_delete_label_frame.pack(fill=tk.X, pady=5)

        char_delete_frame = ttk.Frame(char_delete_label_frame)
        char_delete_frame.pack(fill=tk.X, pady=5)

        ttk.Label(char_delete_frame, text="删除字符位置:").pack(side=tk.LEFT)
        self.delete_pos_var = tk.StringVar()
        self.delete_pos_entry = ttk.Entry(char_delete_frame, textvariable=self.delete_pos_var, width=10)
        self.delete_pos_entry.pack(side=tk.LEFT, padx=(5, 20))
        ttk.Label(char_delete_frame, text="(例如: 1,2,3)").pack(side=tk.LEFT, padx=(0, 20))

        # 添加删除字符数量设置
        ttk.Label(char_delete_frame, text="删除字符数:").pack(side=tk.LEFT)
        self.delete_count_var = tk.StringVar(value="")
        self.delete_count_entry = ttk.Entry(char_delete_frame, textvariable=self.delete_count_var, width=5)
        self.delete_count_entry.pack(side=tk.LEFT, padx=5)
        ttk.Label(char_delete_frame, text="(任意数量)").pack(side=tk.LEFT, padx=5)

        # 添加删除方向选择框架
        delete_direction_frame = ttk.Frame(char_delete_label_frame)
        delete_direction_frame.pack(fill=tk.X, pady=5)

        ttk.Label(delete_direction_frame, text="删除方向:").pack(side=tk.LEFT)
        self.delete_direction_var = tk.StringVar(value="front")
        ttk.Radiobutton(delete_direction_frame, text="从前往后",
                        variable=self.delete_direction_var, value="front",
                        bootstyle="danger-round-toggle").pack(side=tk.LEFT, padx=(5, 20))
        ttk.Radiobutton(delete_direction_frame, text="从后往前",
                        variable=self.delete_direction_var, value="back",
                        bootstyle="danger-round-toggle").pack(side=tk.LEFT)

        # 字符移动功能框架
        char_move_frame = ttk.LabelFrame(advanced_tab, text="字符移动", padding="5", bootstyle="primary")
        char_move_frame.pack(fill=tk.X, pady=5)

        # 添加起始位置和长度设置
        move_pos_frame = ttk.Frame(char_move_frame)
        move_pos_frame.pack(fill=tk.X, pady=5)

        ttk.Label(move_pos_frame, text="起始位置:").pack(side=tk.LEFT)
        self.move_start_pos_var = tk.StringVar()
        self.move_start_pos_entry = ttk.Entry(move_pos_frame, textvariable=self.move_start_pos_var, width=5)
        self.move_start_pos_entry.pack(side=tk.LEFT, padx=(5, 10))

        # 添加字符长度设置
        ttk.Label(move_pos_frame, text="字符长度:").pack(side=tk.LEFT)
        self.move_length_var = tk.StringVar(value="")
        self.move_length_entry = ttk.Entry(move_pos_frame, textvariable=self.move_length_var, width=5)
        self.move_length_entry.pack(side=tk.LEFT, padx=(5, 10))

        # 移动方向和步数
        ttk.Label(move_pos_frame, text="移动方向:").pack(side=tk.LEFT)
        self.move_direction_choice_var = tk.StringVar(value="right")
        ttk.Radiobutton(move_pos_frame, text="向左",
                        variable=self.move_direction_choice_var, value="left",
                        bootstyle="danger-round-toggle").pack(side=tk.LEFT, padx=(5, 10))
        ttk.Radiobutton(move_pos_frame, text="向右",
                        variable=self.move_direction_choice_var, value="right",
                        bootstyle="danger-round-toggle").pack(side=tk.LEFT, padx=(0, 10))

        # 移动步数设置
        ttk.Label(move_pos_frame, text="移动步数:").pack(side=tk.LEFT)
        self.move_steps_var = tk.StringVar(value="")
        self.move_steps_entry = ttk.Entry(move_pos_frame, textvariable=self.move_steps_var, width=5)
        self.move_steps_entry.pack(side=tk.LEFT, padx=(5, 10))

        # 添加计数方向选择
        move_direction_frame = ttk.Frame(char_move_frame)
        move_direction_frame.pack(fill=tk.X, pady=5)

        ttk.Label(move_direction_frame, text="位置计数:").pack(side=tk.LEFT)
        self.move_direction_var = tk.StringVar(value="front")
        ttk.Radiobutton(move_direction_frame, text="从前往后",
                        variable=self.move_direction_var, value="front",
                        bootstyle="danger-round-toggle").pack(side=tk.LEFT, padx=(5, 20))
        ttk.Radiobutton(move_direction_frame, text="从后往前",
                        variable=self.move_direction_var, value="back",
                        bootstyle="danger-round-toggle").pack(side=tk.LEFT)

        # 为了保持兼容性，保留这些变量但不显示在UI上
        self.prefix_var = tk.StringVar()
        self.suffix_var = tk.StringVar()
        self.start_num_var = tk.StringVar(value="1")
        self.num_digits_var = tk.StringVar(value="2")
        self.ext_var = tk.StringVar(value="keep")
        self.new_ext_var = tk.StringVar()
        self.move_target_pos_var = tk.StringVar()  # 保留但不再使用

        # 预览区域
        preview_frame = ttk.LabelFrame(self.main_frame, text="预览", padding="10")
        preview_frame.grid(row=2, column=0, sticky="ew", pady=(0, 10))
        preview_frame.grid_columnconfigure(0, weight=1)

        # 创建上部控制栏（用于文件夹选择）
        preview_control_frame = ttk.Frame(preview_frame)
        preview_control_frame.pack(fill=tk.X, pady=(0, 5))

        ttk.Label(preview_control_frame, text="查看文件夹:").pack(side=tk.LEFT, padx=(0, 5))

        self.folder_filter_var = tk.StringVar(value="[全部]")
        self.folder_filter_combo = ttk.Combobox(
            preview_control_frame,
            textvariable=self.folder_filter_var,
            state="readonly",
            width=40
        )
        self.folder_filter_combo.pack(side=tk.LEFT, fill=tk.X, expand=True)
        self.folder_filter_combo.bind('<<ComboboxSelected>>', lambda e: self.update_preview())

        # 创建预览列表框
        self.preview_listbox = ttk.Treeview(preview_frame, columns=("preview",), show="", height=6)
        self.preview_listbox.pack(fill=tk.BOTH, expand=True)

        # 设置列宽自动调整
        self.preview_listbox.column("preview", width=300, stretch=True)

        # 重命名按钮
        self.rename_btn = ttk.Button(
            self.main_frame,
            text="开始重命名",
            command=self.rename_files,
            bootstyle="danger"
        )
        self.rename_btn.grid(row=3, column=0, pady=(0, 10))

        # 确保根窗口能够正确调整大小
        self.root.bind("<Configure>", self.on_window_resize)

        # 绑定输入变化事件
        self.find_text_var.trace('w', self.update_preview)
        self.replace_text_var.trace('w', self.update_preview)
        self.prepend_text_var.trace('w', self.update_preview)
        self.append_text_var.trace('w', self.update_preview)
        self.number_start_var.trace('w', self.update_preview)
        self.number_marker_var.trace('w', self.update_preview)
        self.delete_pos_var.trace('w', self.update_preview)
        self.delete_count_var.trace('w', self.update_preview)
        self.delete_direction_var.trace('w', self.update_preview)
        self.move_start_pos_var.trace('w', self.update_preview)
        self.move_length_var.trace('w', self.update_preview)
        self.move_direction_choice_var.trace('w', self.update_preview)
        self.move_steps_var.trace('w', self.update_preview)
        self.move_direction_var.trace('w', self.update_preview)

        # 绑定简单修改选项卡的输入变化事件
        self.simple_prefix_var.trace('w', self.update_preview)
        self.simple_suffix_var.trace('w', self.update_preview)
        self.simple_start_num_var.trace('w', self.update_preview)
        self.simple_num_digits_var.trace('w', self.update_preview)
        self.simple_ext_var.trace('w', self.update_preview)
        self.simple_new_ext_var.trace('w', self.update_preview)
        self.segment_rules_var.trace('w', self.update_preview)

    def select_files(self):
        if self.select_mode_var.get() == "files":
            # 文件模式：选择单个或多个文件
            files = filedialog.askopenfilenames(title="选择要重命名的文件")
            if files:
                self.selected_files = list(files)
                self.base_folder = None  # 文件模式不需要基础路径

                # 重置文件夹下拉框
                self.folder_filter_combo['values'] = ["[全部]"]
                self.folder_filter_var.set("[全部]")

                self.file_listbox.delete(*self.file_listbox.get_children())
                for file in self.selected_files:
                    self.file_listbox.insert("", "end", values=(file,))

                # 清除所有输入框的内容
                self.clear_all_inputs()

                # 更新预览
                self.update_preview()
        else:
            # 文件夹模式：递归获取文件夹中所有文件
            folder = filedialog.askdirectory(title="选择文件夹（将递归处理所有子文件夹）")
            if folder:
                self.base_folder = folder  # 保存基础路径用于显示相对路径
                self.selected_files = []

                # 收集所有子文件夹用于下拉框
                subfolders = set()

                # 使用 os.walk 递归遍历所有文件
                for root, dirs, files in os.walk(folder):
                    for file in files:
                        full_path = os.path.join(root, file)
                        self.selected_files.append(full_path)

                        # 收集子文件夹
                        rel_dir = os.path.relpath(root, folder)
                        if rel_dir != ".":
                            subfolders.add(rel_dir)

                # 按路径排序，使显示更有序
                self.selected_files.sort()

                # 更新文件夹下拉框
                folder_list = ["[全部]"] + sorted(subfolders)
                self.folder_filter_combo['values'] = folder_list
                self.folder_filter_var.set("[全部]")

                # 更新列表显示
                self.file_listbox.delete(*self.file_listbox.get_children())
                for file in self.selected_files:
                    # 显示相对路径
                    rel_path = os.path.relpath(file, folder)
                    self.file_listbox.insert("", "end", values=(rel_path,))

                # 清除所有输入框的内容
                self.clear_all_inputs()

                # 更新预览
                self.update_preview()

                # 显示文件数量提示
                messagebox.showinfo("提示", f"已加载 {len(self.selected_files)} 个文件")

    def clear_all_inputs(self):
        """清除所有输入框的内容"""
        # 清除查找替换
        self.find_text_var.set("")
        self.replace_text_var.set("")

        # 清除前缀后缀
        self.prepend_text_var.set("")
        self.append_text_var.set("")

        # 清除序号设置
        self.number_start_var.set("")
        # 保留序号标记的默认值 "@"

        # 清除字符删除设置
        self.delete_pos_var.set("")
        self.delete_count_var.set("")

        # 清除字符移动设置
        self.move_start_pos_var.set("")
        self.move_length_var.set("")
        self.move_steps_var.set("")

        # 清除简单修改选项卡的输入
        self.simple_prefix_var.set("")
        self.simple_suffix_var.set("")
        self.simple_start_num_var.set("1")
        self.simple_num_digits_var.set("2")
        self.simple_new_ext_var.set("")

        # 保留单选按钮的默认值
        # self.delete_direction_var 保持默认值 "front"
        # self.move_direction_choice_var 保持默认值 "right"
        # self.move_direction_var 保持默认值 "front"

    def toggle_simple_rename_options(self):
        """切换简单修改选项卡中重命名选项区域的可用状态"""
        state = "disabled" if self.use_original_simple_var.get() else "normal"

        # 设置所有子控件状态
        for widget in self.simple_rename_options_frame.winfo_children():
            for subwidget in widget.winfo_children():
                if isinstance(subwidget, ttk.Frame):
                    for entry_widget in subwidget.winfo_children():
                        if isinstance(entry_widget, ttk.Entry):
                            entry_widget.configure(state=state)

        # 更新预览
        self.update_preview()

    def toggle_segment_numbering(self):
        """切换分段编号配置区域的可用状态"""
        if self.use_segment_numbering_var.get():
            self.segment_rules_entry.configure(state="normal")
            # 禁用常规编号设置
            self.simple_start_num_entry.configure(state="disabled")
            self.simple_num_digits_entry.configure(state="disabled")
        else:
            self.segment_rules_entry.configure(state="disabled")
            # 启用常规编号设置
            self.simple_start_num_entry.configure(state="normal")
            self.simple_num_digits_entry.configure(state="normal")

        # 更新预览
        self.update_preview()

    def parse_segment_rules(self, rules_str):
        """
        解析分段编号规则
        格式: "1-6:1, 7-:4"
        返回: [(1, 6, '1'), (7, None, '4')]
        """
        segments = []
        if not rules_str.strip():
            return segments

        try:
            parts = rules_str.split(',')
            for part in parts:
                part = part.strip()
                if ':' not in part:
                    continue

                range_part, prefix = part.split(':')
                range_part = range_part.strip()
                prefix = prefix.strip()

                if '-' in range_part:
                    start_str, end_str = range_part.split('-')
                    start = int(start_str.strip()) if start_str.strip() else 1
                    end = int(end_str.strip()) if end_str.strip() else None
                else:
                    # 单个数字表示从该数字到结尾
                    start = int(range_part.strip())
                    end = None

                segments.append((start, end, prefix))
        except Exception as e:
            # 解析失败返回空列表
            return []

        return segments

    def get_segment_prefix(self, index, segments):
        """
        根据文件索引和分段规则获取前缀
        index: 文件索引(从1开始)
        segments: 分段规则列表
        返回: 前缀字符串
        """
        for start, end, prefix in segments:
            if end is None:
                # 没有结束位置，检查是否大于等于起始位置
                if index >= start:
                    return prefix
            else:
                # 有结束位置，检查是否在范围内
                if start <= index <= end:
                    return prefix

        # 如果没有匹配的规则，返回默认前缀
        return "1"

    def is_simple_mode(self):
        """检查当前是否为简单修改模式"""
        try:
            # 获取当前选中的选项卡索引
            current_tab = self.notebook.index(self.notebook.select())
            # 简单修改选项卡是第三个选项卡(索引为2)
            return current_tab == 2
        except:
            return False

    def get_new_extension(self, old_extension):
        """根据用户选择返回新的扩展名"""
        # 始终保持原扩展名
        return old_extension

    def get_new_extension_simple(self, old_extension):
        """简单修改模式:根据用户选择返回新的扩展名"""
        if self.simple_ext_var.get() == "keep":
            return old_extension
        new_ext = self.simple_new_ext_var.get().strip()
        # 确保新扩展名以点号开头
        if new_ext and not new_ext.startswith('.'):
            new_ext = '.' + new_ext
        return new_ext

    def update_preview(self, *args):
        self.preview_listbox.delete(*self.preview_listbox.get_children())
        if not self.selected_files:
            return

        # 获取当前选择的文件夹过滤器
        selected_folder = self.folder_filter_var.get()

        # 过滤文件列表
        if self.base_folder and selected_folder != "[全部]":
            # 只显示选中文件夹下的文件
            filtered_files = []
            for file in self.selected_files:
                rel_path = os.path.relpath(file, self.base_folder)
                file_dir = os.path.dirname(rel_path)
                # 检查文件是否在选中的文件夹或其子文件夹中
                if file_dir.startswith(selected_folder):
                    filtered_files.append(file)
            files_to_preview = filtered_files
        else:
            # 显示所有文件
            files_to_preview = self.selected_files

        if not files_to_preview:
            return

        # 如果是简单修改模式，使用简单版的逻辑
        if self.is_simple_mode():
            # 检查是否使用分段编号
            if self.use_segment_numbering_var.get() and self.base_folder:
                # 分段编号模式：按子文件夹分组处理
                segments = self.parse_segment_rules(self.segment_rules_var.get())
                if not segments:
                    return

                try:
                    num_digits = int(self.simple_num_digits_var.get())
                except ValueError:
                    return

                # 按子文件夹分组
                folder_files = {}
                for file in files_to_preview:
                    folder = os.path.dirname(file)
                    if folder not in folder_files:
                        folder_files[folder] = []
                    folder_files[folder].append(file)

                # 对每个子文件夹内的文件应用分段编号
                for folder, files in sorted(folder_files.items()):
                    counter_map = {}  # 用于跟踪每个前缀的计数器

                    for i, file in enumerate(files, 1):  # 从1开始计数
                        old_name = os.path.basename(file)
                        name_without_ext, old_extension = os.path.splitext(old_name)
                        new_extension = self.get_new_extension_simple(old_extension)

                        # 根据索引获取前缀
                        prefix = self.get_segment_prefix(i, segments)

                        # 更新该前缀的计数器
                        if prefix not in counter_map:
                            counter_map[prefix] = 1
                        else:
                            counter_map[prefix] += 1

                        counter = counter_map[prefix]

                        # 生成新文件名：前缀(计数器)
                        new_name = (f"{self.simple_prefix_var.get()}{prefix}"
                                    f"({str(counter).zfill(num_digits)})"
                                    f"{self.simple_suffix_var.get()}{new_extension}")

                        self.preview_listbox.insert("", "end", values=(f"{old_name} -> {new_name}",))
            else:
                # 常规编号模式
                try:
                    start_num = int(self.simple_start_num_var.get())
                    num_digits = int(self.simple_num_digits_var.get())
                except ValueError:
                    return

                for i, file in enumerate(files_to_preview):
                    old_name = os.path.basename(file)
                    name_without_ext, old_extension = os.path.splitext(old_name)
                    # 获取新的扩展名
                    new_extension = self.get_new_extension_simple(old_extension)

                    # 根据是否保留原文件名决定新文件名格式
                    if self.use_original_simple_var.get():
                        # 只修改扩展名，保留原文件名
                        new_name = f"{name_without_ext}{new_extension}"
                    else:
                        # 使用前缀+编号+后缀+扩展名格式
                        new_name = (f"{self.simple_prefix_var.get()}"
                                    f"{str(start_num + i).zfill(num_digits)}"
                                    f"{self.simple_suffix_var.get()}{new_extension}")

                    # 如果是文件夹模式，只显示文件名
                    if self.base_folder:
                        self.preview_listbox.insert("", "end", values=(f"{old_name} -> {new_name}",))
                    else:
                        self.preview_listbox.insert("", "end", values=(f"{old_name} -> {new_name}",))
            return

        # 复杂模式的原有逻辑
        try:
            start_num = int(self.start_num_var.get())
            num_digits = int(self.num_digits_var.get())
        except ValueError:
            return

        for i, file in enumerate(files_to_preview):
            old_name = os.path.basename(file)
            name_without_ext, old_extension = os.path.splitext(old_name)
            new_extension = self.get_new_extension(old_extension)

            # 在原文件名基础上进行修改
            new_name_without_ext = name_without_ext

            # 应用查找替换
            find_text = self.find_text_var.get()
            replace_text = self.replace_text_var.get()
            if find_text:
                if '@' in find_text:
                    # 将查找文本中的特殊字符转义，并将@替换为数字匹配模式
                    pattern = re.escape(find_text).replace(re.escape('@'), r'\d+')
                    # 使用正则表达式替换，如果替换文本为空，则替换为空字符串
                    new_name_without_ext = re.sub(pattern, replace_text if replace_text else '',
                                                  new_name_without_ext)
                else:
                    new_name_without_ext = new_name_without_ext.replace(find_text, replace_text)

            # 重要：先创建一个副本，用于处理操作顺序的问题
            processed_name = new_name_without_ext

            # 获取前缀后缀和序号标记
            prepend_text = self.prepend_text_var.get()
            append_text = self.append_text_var.get()
            number_marker = self.number_marker_var.get()

            # 应用字符删除功能 - 在应用其他操作之前先执行
            delete_pos = self.delete_pos_var.get()
            try:
                # 获取要删除的字符数量
                delete_count = int(self.delete_count_var.get())
                # 确保删除字符数为正数
                if delete_count <= 0:
                    delete_count = 1
            except ValueError:
                # 如果输入的不是有效数字，默认删除1个字符
                delete_count = 1

            if delete_pos:
                try:
                    # 将输入的位置字符串转换为整数列表，例如"1,2,3" -> [0,1,2]（位置从0开始计算）
                    # 过滤掉非数字输入，并去除空格
                    delete_positions = [int(pos.strip()) - 1 for pos in delete_pos.split(',') if
                                        pos.strip().isdigit()]

                    # 根据删除方向确定位置
                    if self.delete_direction_var.get() == "back":
                        # 从后往前计算位置，将位置转换为从末尾开始的索引
                        # 例如：对于长度为10的字符串，位置1对应索引9, 位置2对应索引8
                        delete_positions = [len(processed_name) - pos - 1 for pos in delete_positions]

                    # 从后向前处理位置，避免删除前面的字符影响后面的位置
                    for pos in sorted(delete_positions, reverse=True):
                        if pos >= 0 and pos < len(processed_name):
                            # 确保不会超出字符串范围
                            if self.delete_direction_var.get() == "front":
                                # 从前往后删除（向右删除）
                                actual_delete_count = min(delete_count, len(processed_name) - pos)
                                processed_name = processed_name[:pos] + processed_name[pos + actual_delete_count:]
                            else:
                                # 从后往前删除（向左删除）
                                # 计算起始删除位置（不能小于0）
                                start_pos = max(0, pos - delete_count + 1)
                                # 删除从start_pos到pos的字符
                                processed_name = processed_name[:start_pos] + processed_name[pos + 1:]
                except ValueError:
                    # 如果输入的位置格式无效，忽略此操作
                    pass

            # 应用字符移动功能
            move_start_pos = self.move_start_pos_var.get().strip()
            move_length = self.move_length_var.get().strip()
            move_direction = self.move_direction_choice_var.get()
            move_steps = self.move_steps_var.get().strip()

            if move_start_pos and move_length and move_steps:
                try:
                    # 转换为整数
                    start_pos = int(move_start_pos) - 1  # 转为0索引
                    length = int(move_length)
                    steps = int(move_steps)

                    # 确保长度和步数为正数
                    if length <= 0:
                        length = 1
                    if steps <= 0:
                        steps = 1

                    # 根据方向调整位置
                    if self.move_direction_var.get() == "back":
                        # 从后往前计算位置
                        name_len = len(processed_name)
                        # 修正：从后往前计算起始位置，但保持长度不变
                        start_pos = name_len - start_pos - length
                        # 确保起始位置不小于0
                        start_pos = max(0, start_pos)

                    # 确保位置在有效范围内
                    if 0 <= start_pos < len(processed_name):
                        # 确保不会超出字符串长度
                        actual_length = min(length, len(processed_name) - start_pos)

                        # 提取要移动的字符
                        move_chars = processed_name[start_pos:start_pos + actual_length]

                        # 创建不包含移动字符的新字符串
                        temp_name = processed_name[:start_pos] + processed_name[start_pos + actual_length:]

                        # 计算目标位置
                        if move_direction == "left":
                            # 向左移动（向前移动）
                            # 如果步数非常大，直接移动到最左边
                            if steps >= start_pos:
                                target_pos = 0
                            else:
                                # 正常移动
                                target_pos = start_pos - steps
                        else:
                            # 向右移动（向后移动）
                            # 如果步数非常大，直接移动到最右边
                            if steps >= len(temp_name) - start_pos:
                                target_pos = len(temp_name)
                            else:
                                # 正常移动
                                target_pos = start_pos + steps

                        # 在目标位置插入这些字符
                        processed_name = temp_name[:target_pos] + move_chars + temp_name[target_pos:]
                except ValueError:
                    # 如果输入的不是有效数字，忽略此操作
                    pass

            # 处理序号插入 - 应用到已处理的名称上
            if number_marker and number_marker in f"{prepend_text}{processed_name}{append_text}":
                start_number = self.number_start_var.get()
                try:
                    # 尝试解析起始序号
                    if '.' in start_number:
                        # 处理小数形式的序号 (如 1.1, 1.2)
                        prefix, num = start_number.rsplit('.', 1)
                        # 保持原始数字的长度
                        num_length = len(num)
                        current_number = f"{prefix}.{str(int(num) + i).zfill(num_length)}"
                    elif start_number.isalpha():
                        # 处理字母序号（如 'a', 'b', 'c' 或 'A', 'B', 'C'）
                        if start_number.islower():  # 小写字母
                            # 计算起始字母的ASCII码
                            start_ascii = ord(start_number)
                            # 计算当前序号的ASCII码
                            current_ascii = start_ascii + i
                            # 如果超过'z'，循环回到'a'
                            while current_ascii > ord('z'):
                                current_ascii = current_ascii - ord('z') + ord('a') - 1
                            current_number = chr(current_ascii)
                        else:  # 大写字母
                            # 计算起始字母的ASCII码
                            start_ascii = ord(start_number)
                            # 计算当前序号的ASCII码
                            current_ascii = start_ascii + i
                            # 如果超过'Z'，循环回到'A'
                            while current_ascii > ord('Z'):
                                current_ascii = current_ascii - ord('Z') + ord('A') - 1
                            current_number = chr(current_ascii)
                    else:
                        # 处理整数形式的序号，保持原始数字的长度
                        num_length = len(start_number)
                        current_number = str(int(start_number) + i).zfill(num_length)
                    # 应用前缀、处理后的名称、后缀，同时替换序号标记
                    new_name_without_ext = f"{prepend_text}{processed_name}{append_text}".replace(
                        number_marker, current_number)
                except ValueError:
                    # 如果序号格式无效，仍然应用前缀和后缀
                    new_name_without_ext = f"{prepend_text}{processed_name}{append_text}"
            else:
                # 如果没有序号标记，直接应用前缀和后缀
                new_name_without_ext = f"{prepend_text}{processed_name}{append_text}"

            new_name = f"{new_name_without_ext}{new_extension}"

            # 如果是文件夹模式，只显示文件名
            if self.base_folder:
                self.preview_listbox.insert("", "end", values=(f"{old_name} -> {new_name}",))
            else:
                self.preview_listbox.insert("", "end", values=(f"{old_name} -> {new_name}",))

    def rename_files(self):
        if not self.selected_files:
            messagebox.showwarning("警告", "请先选择文件！")
            return

        # 如果是简单修改模式，使用简单版的重命名逻辑
        if self.is_simple_mode():
            # 检查是否使用分段编号
            if self.use_segment_numbering_var.get() and self.base_folder:
                # 分段编号模式
                segments = self.parse_segment_rules(self.segment_rules_var.get())
                if not segments:
                    messagebox.showerror("错误", "分段规则格式错误！")
                    return

                try:
                    num_digits = int(self.simple_num_digits_var.get())
                except ValueError:
                    messagebox.showerror("错误", "编号位数必须为数字！")
                    return

                # 检查新扩展名格式
                if self.simple_ext_var.get() == "change":
                    new_ext = self.simple_new_ext_var.get().strip()
                    if not new_ext:
                        messagebox.showerror("错误", "请输入新的扩展名！")
                        return

                try:
                    # 按子文件夹分组
                    folder_files = {}
                    for file in self.selected_files:
                        folder = os.path.dirname(file)
                        if folder not in folder_files:
                            folder_files[folder] = []
                        folder_files[folder].append(file)

                    # 第一步：先将所有文件重命名为临时名称
                    temp_names = {}
                    temp_counter = 0
                    for folder, files in folder_files.items():
                        for file in files:
                            old_path = file
                            old_name = os.path.basename(file)
                            temp_name = f"__TEMP__{temp_counter}__{old_name}"
                            temp_path = os.path.join(folder, temp_name)
                            os.rename(old_path, temp_path)
                            temp_names[temp_path] = (file, folder)
                            temp_counter += 1

                    # 第二步：按子文件夹处理，应用分段编号
                    renamed_count = 0
                    for folder, files in sorted(folder_files.items()):
                        counter_map = {}  # 用于跟踪每个前缀的计数器

                        for i, original_file in enumerate(files, 1):  # 从1开始计数
                            # 找到对应的临时文件
                            temp_path = None
                            for tp, (of, fd) in temp_names.items():
                                if of == original_file:
                                    temp_path = tp
                                    break

                            if not temp_path or not os.path.exists(temp_path):
                                continue

                            old_name = os.path.basename(original_file)
                            name_without_ext, old_extension = os.path.splitext(old_name)
                            new_extension = self.get_new_extension_simple(old_extension)

                            # 根据索引获取前缀
                            prefix = self.get_segment_prefix(i, segments)

                            # 更新该前缀的计数器
                            if prefix not in counter_map:
                                counter_map[prefix] = 1
                            else:
                                counter_map[prefix] += 1

                            counter = counter_map[prefix]

                            # 生成新文件名：前缀(计数器)
                            new_name = (f"{self.simple_prefix_var.get()}{prefix}"
                                        f"({str(counter).zfill(num_digits)})"
                                        f"{self.simple_suffix_var.get()}{new_extension}")

                            new_path = os.path.join(folder, new_name)
                            os.rename(temp_path, new_path)
                            renamed_count += 1

                    messagebox.showinfo("成功", f"文件重命名完成！共处理 {renamed_count} 个文件")
                    self.file_listbox.delete(*self.file_listbox.get_children())
                    self.preview_listbox.delete(*self.preview_listbox.get_children())
                    self.selected_files = []

                except Exception as e:
                    messagebox.showerror("错误", f"重命名时发生错误：{str(e)}")
                    # 尝试恢复
                    try:
                        for temp_path, (original_file, folder) in temp_names.items():
                            if os.path.exists(temp_path):
                                original_name = os.path.basename(original_file)
                                original_path = os.path.join(folder, original_name)
                                if not os.path.exists(original_path):
                                    os.rename(temp_path, original_path)
                    except:
                        pass
            else:
                # 常规编号模式
                try:
                    start_num = int(self.simple_start_num_var.get())
                    num_digits = int(self.simple_num_digits_var.get())
                except ValueError:
                    messagebox.showerror("错误", "起始编号和编号位数必须为数字！")
                    return

                # 检查新扩展名格式
                if self.simple_ext_var.get() == "change":
                    new_ext = self.simple_new_ext_var.get().strip()
                    if not new_ext:
                        messagebox.showerror("错误", "请输入新的扩展名！")
                        return

                try:
                    # 第一步：先将所有文件重命名为临时名称
                    temp_names = {}
                    for i, file in enumerate(self.selected_files):
                        old_path = file
                        directory = os.path.dirname(file)
                        old_name = os.path.basename(file)
                        temp_name = f"__TEMP__{i}__{old_name}"
                        temp_path = os.path.join(directory, temp_name)
                        os.rename(old_path, temp_path)
                        temp_names[temp_name] = (i, old_name, directory)

                    # 第二步：将临时名称重命名为目标名称
                    renamed_count = 0
                    for temp_name, (i, old_name, directory) in temp_names.items():
                        name_without_ext, old_extension = os.path.splitext(old_name)
                        new_extension = self.get_new_extension_simple(old_extension)

                        # 根据是否保留原文件名决定新文件名格式
                        if self.use_original_simple_var.get():
                            # 只修改扩展名，保留原文件名
                            new_name = f"{name_without_ext}{new_extension}"
                        else:
                            # 使用前缀+编号+后缀+扩展名格式
                            new_name = (f"{self.simple_prefix_var.get()}"
                                        f"{str(start_num + i).zfill(num_digits)}"
                                        f"{self.simple_suffix_var.get()}{new_extension}")

                        temp_path = os.path.join(directory, temp_name)
                        new_path = os.path.join(directory, new_name)
                        os.rename(temp_path, new_path)
                        renamed_count += 1

                    messagebox.showinfo("成功", "文件重命名完成！")
                    self.file_listbox.delete(*self.file_listbox.get_children())
                    self.preview_listbox.delete(*self.preview_listbox.get_children())
                    self.selected_files = []

                except Exception as e:
                    messagebox.showerror("错误", f"重命名时发生错误：{str(e)}")
            return

        # 复杂模式的原有逻辑
        try:
            # 检查序号参数，但只在用户输入了数字时进行验证
            start_num_value = self.start_num_var.get()
            if start_num_value and not start_num_value.isalpha():
                # 如果不是字母，尝试将其解析为数字
                start_num = int(self.start_num_var.get())
                num_digits = int(self.num_digits_var.get())
        except ValueError:
            messagebox.showerror("错误", "起始编号和编号位数必须为数字或单个字母！")
            return

        try:
            # 第一步：先将所有文件重命名为临时名称
            temp_names = {}
            for i, file in enumerate(self.selected_files):
                old_path = file
                directory = os.path.dirname(file)
                old_name = os.path.basename(file)
                # 使用唯一标识符创建临时文件名，避免路径问题
                temp_name = f"__TEMP__{i}_{os.getpid()}__{old_name}"
                temp_path = os.path.join(directory, temp_name)

                # 确保临时文件路径有效
                if os.path.exists(old_path):
                    os.rename(old_path, temp_path)
                    temp_names[temp_path] = (i, old_name, directory)
                else:
                    messagebox.showwarning("警告", f"文件不存在: {old_path}")

            # 第二步：将临时名称重命名为目标名称
            renamed_count = 0
            for temp_path, (i, old_name, directory) in temp_names.items():
                # 确保临时文件存在
                if not os.path.exists(temp_path):
                    continue

                name_without_ext, old_extension = os.path.splitext(old_name)
                new_extension = self.get_new_extension(old_extension)

                # 在原文件名基础上进行修改
                new_name_without_ext = name_without_ext

                # 应用查找替换
                find_text = self.find_text_var.get()
                replace_text = self.replace_text_var.get()
                if find_text:
                    if '@' in find_text:
                        # 将查找文本中的特殊字符转义，并将@替换为数字匹配模式
                        pattern = re.escape(find_text).replace(re.escape('@'), r'\d+')
                        # 使用正则表达式替换，如果替换文本为空，则替换为空字符串
                        new_name_without_ext = re.sub(pattern, replace_text if replace_text else '',
                                                      new_name_without_ext)
                    else:
                        new_name_without_ext = new_name_without_ext.replace(find_text, replace_text)

                # 重要：先创建一个副本，用于处理操作顺序的问题
                processed_name = new_name_without_ext

                # 获取前缀后缀和序号标记
                prepend_text = self.prepend_text_var.get()
                append_text = self.append_text_var.get()
                number_marker = self.number_marker_var.get()

                # 应用字符删除功能 - 在应用其他操作之前先执行
                delete_pos = self.delete_pos_var.get()
                try:
                    # 获取要删除的字符数量
                    delete_count = int(self.delete_count_var.get())
                    # 确保删除字符数为正数
                    if delete_count <= 0:
                        delete_count = 1
                except ValueError:
                    # 如果输入的不是有效数字，默认删除1个字符
                    delete_count = 1

                if delete_pos:
                    try:
                        # 将输入的位置字符串转换为整数列表，例如"1,2,3" -> [0,1,2]（位置从0开始计算）
                        # 过滤掉非数字输入，并去除空格
                        delete_positions = [int(pos.strip()) - 1 for pos in delete_pos.split(',') if
                                            pos.strip().isdigit()]

                        # 根据删除方向确定位置
                        if self.delete_direction_var.get() == "back":
                            # 从后往前计算位置，将位置转换为从末尾开始的索引
                            # 例如：对于长度为10的字符串，位置1对应索引9, 位置2对应索引8
                            delete_positions = [len(processed_name) - pos - 1 for pos in delete_positions]

                        # 从后向前处理位置，避免删除前面的字符影响后面的位置
                        for pos in sorted(delete_positions, reverse=True):
                            if pos >= 0 and pos < len(processed_name):
                                # 确保不会超出字符串范围
                                if self.delete_direction_var.get() == "front":
                                    # 从前往后删除（向右删除）
                                    actual_delete_count = min(delete_count, len(processed_name) - pos)
                                    processed_name = processed_name[:pos] + processed_name[pos + actual_delete_count:]
                                else:
                                    # 从后往前删除（向左删除）
                                    # 计算起始删除位置（不能小于0）
                                    start_pos = max(0, pos - delete_count + 1)
                                    # 删除从start_pos到pos的字符
                                    processed_name = processed_name[:start_pos] + processed_name[pos + 1:]
                    except ValueError:
                        # 如果输入的位置格式无效，忽略此操作
                        pass

                # 应用字符移动功能
                move_start_pos = self.move_start_pos_var.get().strip()
                move_length = self.move_length_var.get().strip()
                move_direction = self.move_direction_choice_var.get()
                move_steps = self.move_steps_var.get().strip()

                if move_start_pos and move_length and move_steps:
                    try:
                        # 转换为整数
                        start_pos = int(move_start_pos) - 1  # 转为0索引
                        length = int(move_length)
                        steps = int(move_steps)

                        # 确保长度和步数为正数
                        if length <= 0:
                            length = 1
                        if steps <= 0:
                            steps = 1

                        # 根据方向调整位置
                        if self.move_direction_var.get() == "back":
                            # 从后往前计算位置
                            name_len = len(processed_name)
                            # 修正：从后往前计算起始位置，但保持长度不变
                            start_pos = name_len - start_pos - length
                            # 确保起始位置不小于0
                            start_pos = max(0, start_pos)

                        # 确保位置在有效范围内
                        if 0 <= start_pos < len(processed_name):
                            # 确保不会超出字符串长度
                            actual_length = min(length, len(processed_name) - start_pos)

                            # 提取要移动的字符
                            move_chars = processed_name[start_pos:start_pos + actual_length]

                            # 创建不包含移动字符的新字符串
                            temp_name = processed_name[:start_pos] + processed_name[start_pos + actual_length:]

                            # 计算目标位置
                            if move_direction == "left":
                                # 向左移动（向前移动）
                                # 如果步数非常大，直接移动到最左边
                                if steps >= start_pos:
                                    target_pos = 0
                                else:
                                    # 正常移动
                                    target_pos = start_pos - steps
                            else:
                                # 向右移动（向后移动）
                                # 如果步数非常大，直接移动到最右边
                                if steps >= len(temp_name) - start_pos:
                                    target_pos = len(temp_name)
                                else:
                                    # 正常移动
                                    target_pos = start_pos + steps

                            # 在目标位置插入这些字符
                            processed_name = temp_name[:target_pos] + move_chars + temp_name[target_pos:]
                    except ValueError:
                        # 如果输入的不是有效数字，忽略此操作
                        pass

                # 处理序号插入 - 应用到已处理的名称上
                if number_marker and number_marker in f"{prepend_text}{processed_name}{append_text}":
                    start_number = self.number_start_var.get()
                    try:
                        # 尝试解析起始序号
                        if '.' in start_number:
                            # 处理小数形式的序号 (如 1.1, 1.2)
                            prefix, num = start_number.rsplit('.', 1)
                            # 保持原始数字的长度
                            num_length = len(num)
                            current_number = f"{prefix}.{str(int(num) + i).zfill(num_length)}"
                        elif start_number.isalpha():
                            # 处理字母序号（如 'a', 'b', 'c' 或 'A', 'B', 'C'）
                            if start_number.islower():  # 小写字母
                                # 计算起始字母的ASCII码
                                start_ascii = ord(start_number)
                                # 计算当前序号的ASCII码
                                current_ascii = start_ascii + i
                                # 如果超过'z'，循环回到'a'
                                while current_ascii > ord('z'):
                                    current_ascii = current_ascii - ord('z') + ord('a') - 1
                                current_number = chr(current_ascii)
                            else:  # 大写字母
                                # 计算起始字母的ASCII码
                                start_ascii = ord(start_number)
                                # 计算当前序号的ASCII码
                                current_ascii = start_ascii + i
                                # 如果超过'Z'，循环回到'A'
                                while current_ascii > ord('Z'):
                                    current_ascii = current_ascii - ord('Z') + ord('A') - 1
                                current_number = chr(current_ascii)
                        else:
                            # 处理整数形式的序号，保持原始数字的长度
                            num_length = len(start_number)
                            current_number = str(int(start_number) + i).zfill(num_length)
                        # 应用前缀、处理后的名称、后缀，同时替换序号标记
                        new_name_without_ext = f"{prepend_text}{processed_name}{append_text}".replace(
                            number_marker, current_number)
                    except ValueError:
                        # 如果序号格式无效，仍然应用前缀和后缀
                        new_name_without_ext = f"{prepend_text}{processed_name}{append_text}"
                else:
                    # 如果没有序号标记，直接应用前缀和后缀
                    new_name_without_ext = f"{prepend_text}{processed_name}{append_text}"

                new_name = f"{new_name_without_ext}{new_extension}"

                # 在重命名前检查目标文件是否已存在
                new_path = os.path.join(directory, new_name)
                if os.path.exists(new_path) and temp_path != new_path:
                    # 如果目标文件已存在，添加一个数字后缀
                    base, ext = os.path.splitext(new_name)
                    counter = 1
                    while os.path.exists(os.path.join(directory, f"{base}_{counter}{ext}")):
                        counter += 1
                    new_name = f"{base}_{counter}{ext}"
                    new_path = os.path.join(directory, new_name)

                os.rename(temp_path, new_path)
                renamed_count += 1

            messagebox.showinfo("成功", f"成功重命名 {renamed_count} 个文件！")
            self.file_listbox.delete(*self.file_listbox.get_children())
            self.preview_listbox.delete(*self.preview_listbox.get_children())
            self.selected_files = []

        except Exception as e:
            messagebox.showerror("错误", f"重命名时发生错误：{str(e)}")
            # 在出错时尝试恢复原始文件名
            try:
                for temp_path, (i, old_name, directory) in temp_names.items():
                    if os.path.exists(temp_path):
                        original_path = os.path.join(directory, old_name)
                        if not os.path.exists(original_path):
                            os.rename(temp_path, original_path)
            except:
                pass

    def on_window_resize(self, event):
        # 简化窗口调整大小的处理
        # 由于我们使用grid布局和权重，组件会自动适应窗口大小
        pass


def main():
    # 启用DPI感知
    try:
        from ctypes import windll
        windll.shcore.SetProcessDpiAwareness(1)  # 设置DPI感知
    except:
        pass  # 如果不是Windows系统或无法设置DPI感知，则忽略错误

    root = ttk.Window()
    # 设置窗口初始大小
    root.geometry("857x936")

    # 创建应用实例
    app = BatchRenameApp(root)

    # 设置最小窗口大小
    root.minsize(600, 550)

    # 更新窗口以确保所有组件都已正确布局
    root.update()

    # 获取内容的实际大小
    required_width = app.main_frame.winfo_reqwidth()  # 添加一些边距
    required_height = app.main_frame.winfo_reqheight()

    # 调整窗口大小以适应内容
    root.geometry(f"{required_width}x{required_height}")

    # 允许窗口调整大小
    root.resizable(True, True)

    root.mainloop()


if __name__ == "__main__":
    main()
